package com.dianpingmedia.wifitz.upload;

import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;

import com.dianpingmedia.wifitz.dao.DaoManager;
import com.dianpingmedia.wifitz.entiy.MacFile;
import com.dianpingmedia.wifitz.entiy.ProbeDataInit;
import com.dianpingmedia.wifitz.tcp.client.TcpClientBase;
import com.dianpingmedia.wifitz.tcp.dataObjectDef.BinaryCmdHead;
import com.dianpingmedia.wifitz.utlis.ZipUtil;

import org.greenrobot.greendao.query.QueryBuilder;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;


/**
 * @author zsc
 * @create 2018/6/4 0004
 * @Describe
 */
public class TzDataUploadManager {
    private static final String TAG = "TzDataUploadManager";
    private TcpClientBase mTcpClientBase;
    private Handler mLogHandler;
    private SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss--", Locale.getDefault());
    private SimpleDateFormat mUploadDateFormat = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
    //最大重试时间为2分钟
    private static final int MAX_RETRY_TIME = 120 * 1000;
    private int currRetryTime = 3000;
    private final static int ERROR_TRY_MAX_TIMES = 3;

    private Handler mUploadHandler;

    public TzDataUploadManager() {
        mTcpClientBase = new TcpClientBase();
        HandlerThread handlerThread = new HandlerThread("TzDataUploadManager");
        handlerThread.start();
        mUploadHandler = new Handler(handlerThread.getLooper());
    }

    private void writeTzData(final MacFile macFile) {
        byte[] rawBytes = macFile.getFile();
        try {
            byte[] unZip = ZipUtil.unZip(rawBytes);
            String raw = new String(unZip, "ASCII");
            Log.d("TzDataUploadManager", "解压还原:" + raw);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        byte[] bytes = new BinaryCmdHead(BinaryCmdHead.C_CMD_WIFI_PROBE_SEND_DATA, rawBytes, rawBytes.length).getBytes();
        Log.d(TAG, "加入命令后的数据:" + new String(bytes));
        mTcpClientBase.write(bytes);
        Log.d(TAG, "bytes.size=" + bytes.length);
        int length = mTcpClientBase.read();
        sendLog("收到服务器的数据长度为" + length);
        if (length <= 0) {
            onFail();
        } else {
            byte[] recvBytes = mTcpClientBase.getRecvBytes();
            BinaryCmdHead binaryCmdHead = new BinaryCmdHead();
            binaryCmdHead.parse(recvBytes, recvBytes.length, false);
            int cmd = binaryCmdHead.getCmd();
            sendLog("服务器返回CMD=" + cmd);
            if (cmd == BinaryCmdHead.C_CMD_WIFI_PROBE_SEND_NEXT_DATA) {
                //成功发送下一个
                sendLog("服务器接收成功，继续发送下一个");
                onSuccess(macFile);
            } else if (cmd == BinaryCmdHead.C_CMD_WIFI_PROBE_ZIP_ERROR) {
                //错误，重试3次
                sendLog("服务器接收失败，重试");
                if (macFile.addErrorTimes() < ERROR_TRY_MAX_TIMES) {
                    writeTzData(macFile);
                } else {
                    sendLog("服务器接收失败，重试次数已到，丢弃此数据");
                    deleteOneByIdAndSaveError(macFile);
                }
            }
        }
    }

    private boolean writeTzInit(ProbeDataInit probeDataInit) {
        String initStr = probeDataInit.toString();
        sendLog("发送初始化命令:" + initStr);
        try {
            byte[] rawInitBytes = initStr.getBytes("ASCII");
            byte[] addCmdBytes = new BinaryCmdHead(BinaryCmdHead.C_CMD_WIFI_PROBE_SEND_INIT, rawInitBytes, rawInitBytes.length).getBytes();
            mTcpClientBase.write(addCmdBytes);
            int length = mTcpClientBase.read();
            sendLog("初始化收到服务器的数据长度为" + length);
            if (length <= 0) {
                onFail();
                return false;
            } else {
                byte[] recvBytes = mTcpClientBase.getRecvBytes();
                BinaryCmdHead binaryCmdHead = new BinaryCmdHead();
                binaryCmdHead.parse(recvBytes, recvBytes.length, false);
                int cmd = binaryCmdHead.getCmd();
                sendLog("初始化收到服务器返回CMD=" + cmd);
                if (cmd == BinaryCmdHead.C_CMD_WIFI_PROBE_SEND_NEXT_DATA) {
                    //正常开始做上传数据
                    sendLog("初始化成功，可以传送数据了");
                    return true;
                } else {
                    sendLog("初始化失败，退避继续进行");
                    onFail();
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return false;
    }

    private void deleteOneByIdAndSaveError(MacFile macFile) {
        deleteOneById(macFile.getId());
        currRetryTime = 3000;
        sendLog("删除数据库中数据id=" + macFile.getId());
        mUploadHandler.postDelayed(uploadRunnable, 3000);
    }

    private void onSuccess(MacFile macFile) {
        sendLog("数据发送成功");
        currRetryTime = 3000;
        //删除数据
        sendLog("删除数据库中数据id=" + macFile.getId());
        deleteOneById(macFile.getId());
        //2秒后继续上传
        mUploadHandler.postDelayed(uploadRunnable, 3000);
    }

    private void onFail() {
        mTcpClientBase.close();
        currRetryTime = (int) (currRetryTime + (Math.random() * 5000 + 2000));
        if (currRetryTime > MAX_RETRY_TIME) {
            currRetryTime = MAX_RETRY_TIME;
        }
        sendLog("连接服务器失败,等待" + currRetryTime / 1000 + "秒重试");
        //        mUploadHandler.postDelayed(connectRunnable, currRetryTime);
        mUploadHandler.postDelayed(connectRunnable, currRetryTime);
    }

    public void release() {
        try {
            mTcpClientBase.close();
            mUploadHandler.removeCallbacksAndMessages(null);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                mUploadHandler.getLooper().quitSafely();
            } else {
                mUploadHandler.getLooper().quit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void startUpload() {
        if (mTcpClientBase.isChange()) {
            currRetryTime = 3000;
            sendLog("数据上传的ip与端口发生变化，重新启动上传服务");
        }
        mUploadHandler.removeCallbacksAndMessages(null);
        mUploadHandler.post(connectRunnable);
    }

    public void setHandler(Handler handler) {
        mLogHandler = handler;
        mTcpClientBase.setHandler(mLogHandler);
    }


    private Runnable connectRunnable = new Runnable() {
        @Override
        public void run() {
            boolean connect = mTcpClientBase.connect();
            if (connect) {
                long delayMillis = (long) (Math.random() * 4000 + 1000);
                sendLog("连接服务器成功，随机1-5秒后开始汇报");
                mUploadHandler.postDelayed(uploadRunnable, delayMillis);
            } else {
                onFail();
            }
        }
    };


    private Runnable uploadRunnable = new Runnable() {
        @Override
        public void run() {
            List<MacFile> macFiles = queryOne();
            if (macFiles != null && macFiles.size() > 0) {
                if (mTcpClientBase.isConnect()) {
                    //不相同发送
                    MacFile macFile = macFiles.get(0);
                    ProbeDataInit probeDataInit = new ProbeDataInit();
                    probeDataInit.setM_strWiFiProbeMac(macFile.getWiFiProbeMac());
                    probeDataInit.setM_strDate(mUploadDateFormat.format(macFile.getTime()));
                    probeDataInit.setM_strDestMac(macFile.getDestMac());
                    probeDataInit.setDestMacsJson(macFile.getJsonDestMac());

                    if (mTcpClientBase.equalsProbeDataInit(probeDataInit)) {
                        //不同发送重新发送init
                        sendLog("init不同重新发送");
                        boolean goDoTask = writeTzInit(probeDataInit);
                        //提交初始化成功，开始做上传
                        if (goDoTask) {
                            doTask(macFile);
                        }
                    } else {
                        sendLog("init相同不重新发送");
                        //相同不重复发送init，继续发送数据包
                        doTask(macFile);
                    }
                } else {
                    onFail();
                }
            } else {
                sendLog("数据库中无上传数据,关闭连接，退避1分钟再次尝试上传");
                mTcpClientBase.close();
                mUploadHandler.postDelayed(connectRunnable, 60 * 1000);
            }
        }
    };

    private void doTask(MacFile macFile) {
        if (macFile.getFile() != null && macFile.getFile().length > 0) {
            writeTzData(macFile);
        } else {
            sendLog("id=" + macFile.getId() + " 此条数据异常，删除");
            deleteOneById(macFile.getId());
            //2秒继续上传下一条
            mUploadHandler.postDelayed(uploadRunnable, 2000);
        }
    }


    /**
     * 取出一个比当天0点晚的一条数据
     *
     * @return
     */
    private List<MacFile> queryOne() {
        QueryBuilder<MacFile> macFileQueryBuilder = DaoManager.getInstance().getDaoSession().getMacFileDao().queryBuilder();
        //测试使用
        return macFileQueryBuilder.limit(1).list();
        //下面是正式使用
        //        Calendar calendar = Calendar.getInstance();
        //        calendar.setTime(new Date());
        //        calendar.set(Calendar.HOUR_OF_DAY, 0);
        //        calendar.set(Calendar.MINUTE, 0);
        //        calendar.set(Calendar.SECOND, 0);
        //        return macFileQueryBuilder.where(MacFileDao.Properties.Time.lt(calendar.getTime().getTime())).limit(1).list();
    }

    private void deleteOneById(long id) {
        DaoManager.getInstance().getDaoSession().getMacFileDao().deleteByKey(id);
    }

    private void sendLog(String log) {
        Log.d(TAG, log);
        if (mLogHandler != null) {
            Message obtain = Message.obtain();
            obtain.what = 1;
            obtain.obj = getCurrTime() + log;
            mLogHandler.sendMessage(obtain);
        }
    }

    private String getCurrTime() {
        return mDateFormat.format(new Date());
    }
}
